package com.bestcem.xm.ticket.service.manager.notify;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.ticket.config.TicketDingTalkProperties;
import com.bestcem.xm.ticket.config.TicketWechatWorkProperties;
import com.bestcem.xm.ticket.dao.TicketConfigDao;
import com.bestcem.xm.ticket.dao.TicketNotifyConfigDao;
import com.bestcem.xm.ticket.entity.mongo.NotifySetting;
import com.bestcem.xm.ticket.entity.mongo.Ticket;
import com.bestcem.xm.ticket.entity.mongo.TicketNotifyConfig;
import com.bestcem.xm.ticket.enums.*;
import com.bestcem.xm.ticket.grpc.client.TicketBaseUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.dto.user.OrganizationDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.SmtpDTO;
import com.bestcem.xm.ticket.grpc.client.enums.messagecenter.TemplateTypeEnum;
import com.bestcem.xm.ticket.service.TicketNotifySettingService;
import com.bestcem.xm.ticket.service.manager.notify.dto.NotifyMessageDTO;
import com.bestcem.xm.ticket.service.manager.role.BaseTicketRole;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工单通知 工具类
 * 工单/预警 所有的通知都在这里
 * 收到预警/收到工单/工单即将逾期/工单逾期
 *
 * @author gy.liu
 * @version 1.0
 * @date 2021/8/23 10:04
 **/
@Slf4j
@Component
public class TicketNotifyUtil {

    // 工单事件转换为通知事件
    private static final Map<TicketEventEnum, TicketNotifyConfigEventEnum> eventMap = new HashMap<>();

    static {
        eventMap.put(TicketEventEnum.SYSTEM_CREATED, TicketNotifyConfigEventEnum.CREATED_TICKET);
        eventMap.put(TicketEventEnum.FOLLOWING, TicketNotifyConfigEventEnum.CREATED_TICKET);
        eventMap.put(TicketEventEnum.COMMIT_FOLLOWED, null);
        eventMap.put(TicketEventEnum.FOLLOW_OVERDUE_REMIND, TicketNotifyConfigEventEnum.FOLLOW_REMIND);
        eventMap.put(TicketEventEnum.FOLLOW_OVERDUE, TicketNotifyConfigEventEnum.FOLLOW_OVERDUE);
        eventMap.put(TicketEventEnum.AUDITING, TicketNotifyConfigEventEnum.RECEIVE_AUDIT);
        eventMap.put(TicketEventEnum.COMMIT_AUDITED, null);
        eventMap.put(TicketEventEnum.AUDIT_OVERDUE_REMIND, TicketNotifyConfigEventEnum.AUDIT_REMIND);
        eventMap.put(TicketEventEnum.AUDIT_OVERDUE, TicketNotifyConfigEventEnum.AUDIT_OVERDUE);
        eventMap.put(TicketEventEnum.TRANSFER_FOLLOW, TicketNotifyConfigEventEnum.CHANGE_FOLLOW);
        eventMap.put(TicketEventEnum.UNDEED_DEAL, TicketNotifyConfigEventEnum.ONLY_NOTIFY);
    }

    @Resource
    private TicketBaseUserGrpcService ticketBaseUserGrpcService;

    @Resource
    private TicketNotifySettingService ticketNotifySettingService;

    @Resource
    private TicketNotifyConfigDao ticketNotifyConfigDao;
    @Resource
    private TicketConfigDao ticketConfigDao;

    @Resource
    private NotifyManager notifyUtil;
    @Resource
    private RenderManager renderManager;
    @Resource
    private ContentManager contentManager;
    @Resource
    private AddressManager addressManager;
    @Resource
    private TemplateManager templateManager;

    @Resource
    private TicketDingTalkProperties ticketDingTalkProperties;
    @Resource
    private TicketWechatWorkProperties ticketWechatWorkProperties;

    /**
     * 项目名字
     */
    @Value("${app.xm.name:倍市得CEM}")
    private String xmName;


    public void notifyMsg(Ticket ticket, BaseTicketRole roleDTO, TicketEventEnum ticketEvent) {
        try {
            // 根据事件类型发送不同类型的邮件给配置中的角色
            TicketNotifyConfigEventEnum notifyEvent = eventMap.get(ticketEvent);
            // 提交跟进和提交审核工单事件无对应的工单通知事件
            if (Objects.isNull(notifyEvent)) {
                if (log.isInfoEnabled()) {
                    log.info("NOTIFY:工单事件没有对应的通知");
                }
                return;
            }
            if (log.isInfoEnabled()) {
                log.info("NOTIFY:工单事件: {}通知事件: {}", ticketEvent, notifyEvent);
            }
            // 查询工单通知配置和是否开启
            TicketNotifyConfig notifyConfig =
                    ticketNotifyConfigDao.findNotifyConfigByIdEvent(ticket.getTicketConfigId(), notifyEvent.getIndex());
            if (log.isInfoEnabled()) {
                log.info("NOTIFY:工单通知配置:{}", notifyConfig.getId());
            }
            if (!TicketNotifyConfigStatusEnum.ENABLED.getIndex().equals(notifyConfig.getStatus())) {
                if (log.isInfoEnabled()) {
                    log.info("NOTIFY:工单通知: 关闭 结束通知流程");
                }
                return;
            }
            if (Boolean.FALSE.equals(notifyConfig.getHasReceiver())) {
                if (log.isInfoEnabled()) {
                    log.info("NOTIFY:工单通知: 关闭通知处理人 结束通知流程");
                }
                return;
            }


            NotifySetting.Way ways = notifyConfig.getWays();
            if (Objects.isNull(ways)) {
                ways = new NotifySetting.Way();
                // 兼容旧版数据
                ways.setEmail(TicketNotifyConfigStatusEnum.ENABLED.getIndex().equals(notifyConfig.getStatus()));
            }
            if (StringUtils.isEmpty(ticket.getOrgId())) {
                log.info("NOTIFY:orgId is null");
            }
            // 获取通知配置信息
            if (log.isInfoEnabled()) {
                log.info("NOTIFY:工单通知:findByOrgId:{}", ticket.getOrgId());
            }
            ServiceResult<NotifySetting> notifySettingResult = ticketNotifySettingService.getEntityByOrgId(ticket.getOrgId());
            NotifySetting notifySetting = notifySettingResult.getData();
            if (Objects.isNull(notifySetting)) {
                log.error("NOTIFY:工单通知 {} notifySetting is null", ticket.getOrgId());
            }
            NotifySetting.Way globalWays = notifySetting.getWays();
            if (Objects.isNull(globalWays)) {
                globalWays = new NotifySetting.Way();
                globalWays.setEmail(true);
            }
            // 根据ticket.getOrgId()查询机构信息
            OrganizationDTO organizationDTO = ticketBaseUserGrpcService.getOrganization(ticket.getOrgId());
            if (Objects.isNull(organizationDTO)) {
                log.error("[Ticket] Organization id= {} not found:", ticket.getOrgId());
                return;
            }
            if (log.isInfoEnabled()) {
                log.info("[Ticket] NOTIFY:获取机构信息:{}", organizationDTO.getCode());
            }
            // 系统名称
            String sysName = xmName;
            if (Objects.nonNull(organizationDTO.getSkin()) && Boolean.TRUE.equals(Boolean.valueOf(organizationDTO.getSkin().getStatus()))) {
                if (!ObjectUtils.isEmpty(organizationDTO.getSkin().getName())) {
                    sysName = organizationDTO.getSkin().getName();
                }
            }

            // 预警设置
            if (Objects.isNull(roleDTO)) {
                ticket.setType(TicketTypeEnum.UN_NEED_DEAL.getIndex());
            }

            // 邮件处理 (消息库版)
            if (Boolean.TRUE.equals(globalWays.getEmail()) && Boolean.TRUE.equals(ways.getEmail())) {
                mailProcess(notifyConfig, ticket, sysName);
            }
            // 短信处理 (消息库版)
            if (Boolean.TRUE.equals(globalWays.getSms()) && Boolean.TRUE.equals(ways.getSms())) {
                smsProcess(notifyConfig, ticket, sysName);
            }
            // 飞书处理 (触发条件名称版)
            if (Boolean.TRUE.equals(globalWays.getFeiShu()) && Boolean.TRUE.equals(ways.getFeiShu())) {
                feiShuProcess(notifyConfig, ticket, organizationDTO.getCode());
            }
            // 钉钉处理
            if (Boolean.TRUE.equals(globalWays.getDingtalk()) && Boolean.TRUE.equals(ways.getDingtalk())) {
                dingTalkProcess(notifyConfig, ticket);
            }
            // 企业微信处理
            if (Boolean.TRUE.equals(globalWays.getWeChatWork()) && Boolean.TRUE.equals(ways.getWeChatWork())) {
                wechatWorkProcess(notifyConfig, ticket);
            }

        } catch (Exception e) {
            log.error("[Ticket] NOTIFY 处理异常", e);
        }
    }


    /**
     * 短信处理 (消息库版)
     *
     * @param notifyConfig 通知配置
     * @param ticket       工单信息
     * @param sysName      系统名字
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/11/22 17:00
     */
    private void smsProcess(TicketNotifyConfig notifyConfig, Ticket ticket, String sysName) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY 短信处理 smsProcessNew");
        }

        // 问卷id
        String surveyId = ticket.getSurveyId();
        // 公司id
        String orgId = ticket.getOrgId();
        // 通知事件
        TicketNotifyConfigEventEnum notifyEvent = TicketNotifyConfigEventEnum.getByIndex(notifyConfig.getEvent());
        if (Objects.isNull(notifyEvent)) {
            log.error("[Ticket] NOTIFY smsProcessNew notifyEvent is null");
            return;
        }

        // 接收人手机号
        Set<String> receivers = addressManager.getReceiverAddress(ticket, notifyConfig, TicketNotifyChannelEnum.SMS);
        // 接收人为空, 则不发送
        if (CollectionUtils.isEmpty(receivers)) {
            log.error("[Ticket] NOTIFY smsProcessNew receivers is null");
            return;
        }
        // 抄送人手机号
        Set<String> ccs = addressManager.getCcAddressNew(ticket, notifyConfig, TicketNotifyChannelEnum.SMS);
        // 收件人抄送人取并集
        receivers.addAll(ccs);

        // --- 获取通知消息 ---
        // 获取模板
        String contentTemplate = notifyConfig.getSmsContent();
        if (ObjectUtils.isEmpty(contentTemplate)) {
            NotifyMessageDTO defaultTemplate = templateManager.getDefaultTemplate(orgId, notifyEvent, TemplateTypeEnum.SMS);
            contentTemplate = defaultTemplate.getContent();
        }
        NotifyMessageDTO message = new NotifyMessageDTO(notifyConfig.getSmsSubject(), contentTemplate);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY smsProcessNew MessageTemplate {}", message);
        }
        // 获取自定义字段数据
        Map<String, String> messageData = contentManager.getSmsData(ticket, sysName);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY smsProcessNew MessageData {}", messageData);
        }
        // 填充模板数据
        message = renderManager.smsRender(message, messageData);

        // 短信内容
        String content = message.getContent();
        // 发短信
        for (String phone : receivers) {
            if (ObjectUtils.isEmpty(phone)) {
                continue;
            }
            if (log.isInfoEnabled()) {
                log.info("[Ticket] smsProcessNew {},{},{}", phone, content, surveyId);
            }
            notifyUtil.sendSms(orgId, surveyId, "", content, phone, SMSRecordTypeEnum.TICKET.getIndex());
        }
    }


    /**
     * 邮件处理 (消息库版)
     *
     * @param notifyConfig 工单通知配置
     * @param ticket       工单信息
     * @param sysName      系统名字
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/11/23 11:28
     */
    private void mailProcess(TicketNotifyConfig notifyConfig, Ticket ticket, String sysName) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY 邮件处理 mailProcessNew");
        }

        // 公司id
        String orgId = ticket.getOrgId();
        // 通知事件
        TicketNotifyConfigEventEnum notifyEvent = TicketNotifyConfigEventEnum.getByIndex(notifyConfig.getEvent());
        if (Objects.isNull(notifyEvent)) {
            log.error("[Ticket] NOTIFY mailProcessNew notifyEvent is null");
            return;
        }

        // 接收人邮箱
        Set<String> receivers = addressManager.getReceiverAddress(ticket, notifyConfig, TicketNotifyChannelEnum.EMAIL);
        // 接收人为空, 则不发送
        if (CollectionUtils.isEmpty(receivers)) {
            log.error("[Ticket] NOTIFY mailProcessNew receivers is null");
            return;
        }
        // 抄送人邮箱
        Set<String> ccs = addressManager.getCcAddressNew(ticket, notifyConfig, TicketNotifyChannelEnum.EMAIL);

        // --- 获取通知消息 ---
        // 获取模板
        String subjectTemplate = notifyConfig.getEmailSubject(), contentTemplate = notifyConfig.getEmailContent();
        if (ObjectUtils.isEmpty(subjectTemplate) && ObjectUtils.isEmpty(contentTemplate)) {
            NotifyMessageDTO defaultTemplate = templateManager.getDefaultTemplate(orgId, notifyEvent, TemplateTypeEnum.EMAIL);
            subjectTemplate = defaultTemplate.getSubject();
            contentTemplate = defaultTemplate.getContent();
        }
        NotifyMessageDTO message = new NotifyMessageDTO(subjectTemplate, contentTemplate);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY mailProcessNew MessageTemplate {}", message);
        }
        // 获取自定义字段数据
        Map<String, String> messageData = contentManager.getEmailData(ticket, sysName, message);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY mailProcessNew MessageData {}", JSONObject.toJSONString(messageData));
        }
        // 填充模板数据
        message = renderManager.emailRender(message, messageData);

        // 邮件主题/邮件内容
        String subject = message.getSubject(), content = message.getContent();
        // 获取 smtpId
        String smtpId = notifyConfig.getSmtpId();
        if (ObjectUtils.isEmpty(smtpId)) {
            // 获取用户默认的邮箱
            List<SmtpDTO> smtpDTOS = ticketBaseUserGrpcService.listSmtpByOrgId(ticket.getOrgId(), true);
            if (CollectionUtils.isEmpty(smtpDTOS)) {
                log.error("[Ticket] NOTIFY 获取租户邮箱新失败");
                return;
            }
            if (log.isInfoEnabled()) {
                log.info("[Ticket] NOTIFY mailProcessNew listSmtpByOrgId {}", JSONObject.toJSONString(smtpDTOS));
            }
            List<SmtpDTO> emails = smtpDTOS.stream().filter(SmtpDTO::isNotice).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(emails)) {
                log.error("[Ticket] NOTIFY 获取默认邮箱新失败");
                return;
            }
            // 调用发邮件接口
            notifyUtil.sendEmail(receivers, ccs, subject, content, null, emails.get(0));
        } else {
            // 调用发邮件接口
            notifyUtil.sendEmail(receivers, ccs, subject, content, smtpId, null);
        }
    }


    /**
     * 飞书处理 (触发条件名称版)
     *
     * @param notifyConfig 工单通知配置
     * @param ticket       工单信息
     * @param orgCode      公司code
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2022/2/18 11:34
     */
    private void feiShuProcess(TicketNotifyConfig notifyConfig, Ticket ticket, String orgCode) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY 飞书处理 feiShuProcessNew");
        }

        // 接收人邮箱
        Set<String> receivers = addressManager.getReceiverAddress(ticket, notifyConfig, TicketNotifyChannelEnum.EMAIL);
        // 接收人为空, 则不发送
        if (CollectionUtils.isEmpty(receivers)) {
            log.error("[Ticket] NOTIFY feiShuProcessNew receivers is null");
            return;
        }
        // 抄送人邮箱
        Set<String> ccs = addressManager.getCcAddressNew(ticket, notifyConfig, TicketNotifyChannelEnum.EMAIL);
        // 收件人抄送人取并集
        receivers.addAll(ccs);

        // 通知事件
        TicketNotifyConfigEventEnum notifyEvent = TicketNotifyConfigEventEnum.getByIndex(notifyConfig.getEvent());
        if (Objects.isNull(notifyEvent)) {
            log.error("[Ticket] NOTIFY feiShuProcessNew notifyEvent is null");
            return;
        }

        // --- 获取通知消息 ---
        // 获取自定义字段内容
        Map<String, String> messageData = contentManager.getFeiShuData(ticket);
        // 获取模板 TODO: 这里可以优化, 改成模板动态拼接, 我没时间写, 看后面谁有缘分吧
        boolean hasTrigger = messageData.containsKey(FiledConstant.FeiShu.TRIGGER_NAME);
        String template = FeishuTemplate.getTemplate(notifyEvent, hasTrigger);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY feiShuProcessNew MessageData {}", JSONObject.toJSONString(messageData));
        }
        // 渲染模板
        String message = renderManager.feiShuRender(template, messageData);

        // 飞书消息发送
        receivers.forEach(email -> notifyUtil.sendFeiShuByOrgCode(orgCode, email, message));
    }


    /**
     * 钉钉处理
     *
     * @param notifyConfig 工单通知配置
     * @param ticket       工单信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/12/1 17:54
     */
    private void dingTalkProcess(TicketNotifyConfig notifyConfig, Ticket ticket) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY 钉钉处理 dingTalkProcess");
        }

        // 通知事件
        TicketNotifyConfigEventEnum notifyEvent = TicketNotifyConfigEventEnum.getByIndex(notifyConfig.getEvent());
        if (Objects.isNull(notifyEvent)) {
            log.error("[Ticket] NOTIFY dingTalkProcess notifyEvent is null");
            return;
        }

        // 接收人userId
        Set<String> receiverUserIds = addressManager.getReceiverAddress(ticket, notifyConfig, TicketNotifyChannelEnum.DING_TALK);
        // 接收人为空, 则不发送
        if (CollectionUtils.isEmpty(receiverUserIds)) {
            log.error("[Ticket] NOTIFY dingTalkProcess receivers is null");
            return;
        }
        // 抄送人userId
        Set<String> ccUserIds = addressManager.getCcAddressNew(ticket, notifyConfig, TicketNotifyChannelEnum.DING_TALK);
        // 收件人抄送人取并集
        receiverUserIds.addAll(ccUserIds);

        // --- 获取通知消息 ---
        // 获取模板Id
        String templateId = ticketDingTalkProperties.getTemplateId(notifyEvent);
        if (ObjectUtils.isEmpty(templateId)) {
            log.error("[Ticket] NOTIFY dingTalkProcess templateId is null");
            return;
        }
        // 获取自定义字段数据
        Map<String, String> messageData = contentManager.getDingTalkData(ticket);

        // 调用发钉钉接口
        notifyUtil.sendDingTalk(receiverUserIds, templateId, JSON.toJSONString(messageData));
    }


    /**
     * 企业微信处理
     *
     * @param notifyConfig 工单通知配置
     * @param ticket       工单信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/12/1 17:54
     */
    public void wechatWorkProcess(TicketNotifyConfig notifyConfig, Ticket ticket) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] NOTIFY 企业微信处理 wechatWorkProcess");
        }

        // 通知事件
        TicketNotifyConfigEventEnum notifyEvent = TicketNotifyConfigEventEnum.getByIndex(notifyConfig.getEvent());
        if (Objects.isNull(notifyEvent)) {
            log.error("[Ticket] NOTIFY wechatWorkProcess notifyEvent is null");
            return;
        }

        // 接收人userId
        Set<String> receiverUserIds = addressManager.getReceiverAddress(ticket, notifyConfig, TicketNotifyChannelEnum.WECHAT_WORK);
        // 接收人为空, 则不发送
        if (CollectionUtils.isEmpty(receiverUserIds)) {
            log.error("[Ticket] NOTIFY wechatWorkProcess receivers is null");
            return;
        }
        // 抄送人userId
        Set<String> ccUserIds = addressManager.getCcAddressNew(ticket, notifyConfig, TicketNotifyChannelEnum.WECHAT_WORK);
        // 收件人抄送人取并集
        receiverUserIds.addAll(ccUserIds);

        // --- 获取通知消息 ---
        // 获取 page; @以诺(昌鹏涛) 我们发送企业微信消息不用管appId
        String page = ticketWechatWorkProperties.getPage();
        page = String.format(page, ticket.getId());
        // 获取 title
        String title = FiledConstant.WechatWork.TITLE_MAP.getOrDefault(notifyEvent, "收到工单");
        // 获取自定义字段数据
        Map<String, String> messageData = contentManager.getWechatWorkData(ticket);

        // 调用发企业微信接口
        notifyUtil.sendWechatWork(ticket.getOrgId(), receiverUserIds, page, title, null, messageData);
    }
}
